#!/usr/bin/env python2

import os
import sys
import socket
import time
import subprocess
import fcntl
import types
import errno
import getopt
import random

from config import Config
from utils import Exp, _dmsg, _dwarn, _derror, _str2dict, _getrack
from movedata import Object, Replica, Node, Location, Rack
from nodepool import NodePool

class Movebylocation:
    def __init__(self, storage):
        self.storage = storage
        self.objectbydict = {}
        self.pool = NodePool(storage)

    def addobject(self, name):
        if (len(self.pool.racks) == 0):
            raise Exp(errno.ENOENT, "no rack exist")
        elif (len(self.pool.racks) == 1):
            _dwarn("only one rack")
            return

        obj = Object(self.storage, name)
        rack = {}

        repnum = len(obj.location)
        for i in range(repnum):
            loc = obj.location[i]
            r = _getrack(loc)
            if (rack.get(r) != None):
                obj.location[i] = None
            else:
                rack[r] = loc

        if (len(rack) >= len(self.pool.racks)):
            return

        if (len(rack) == repnum):
            return

        _dmsg("object %s need move" % (name))

        if (self.objectbydict.get(name)):
            raise Exp(errno.EEXIST, "%s exist" % (name))
        self.objectbydict[name] = obj

    def move(self):
        if (len(self.pool.racks) == 0):
            raise Exp(errno.ENOENT, "no rack exist")
        elif (len(self.pool.racks) == 1):
            return

        for (k, v) in self.objectbydict.items():
            v.needmove = True
            v.move(self.pool)

class Movebycapcity:
    def __init__(self, storage):
        self.storage = storage
        self.nodebydict = {}
        self.objectbydict = {}

        nodelist = storage.list_node()
        for i in nodelist:
            self.nodebydict[i] = Node(storage, i)
        
    def addobject(self, name):
        if (self.objectbydict.get(name)):
            raise Exp(errno.EEXIST, "%s exist" % (name))
        obj = Object(self.storage, name)
        self.objectbydict[name] = obj

        for loc in obj.location:
            # print("add %s into %s" % (str(obj), loc))
            if (self.nodebydict.get(loc)):
                self.nodebydict[loc].add(obj)

    def needmove(self):
        return True

        self.nodelist = sorted(self.nodelist, cmp=lambda x, y:cmp(x.free, y.free), reverse=True)
        if (self.nodelist[0].free - self.nodelist[-1].free < (1024 * 1024 * 1024 * 1024)):
            return False
        return True

    def move(self):
        du = 0
        capacity = 0
        self.nodelist = []
        for (k, v) in self.nodebydict.items():
            self.nodelist.append(v)
            du = du + v.du
            capacity = capacity + v.capacity

        if (self.needmove() == False):
            return

        percent = float(du) / float(capacity)

        _dmsg("percent %f %u/%u" % (percent, du, capacity))

        pool = NodePool(self.storage)
        for i in self.nodelist:
            # print ("node %s " % (str(i)))
            poplist = i.pop((percent + 0.1) * i.capacity)
            if (poplist):
                pool.remove(i.name)
                for o in poplist:
                    self.objectbydict[o].location_clear(i.name)

        for (k, v) in self.objectbydict.items():
            v.move(pool)

class Movebyconnection:
    def __init__(self, storage):
        self.storage = storage

    def move(self, name):
        obj = Object(self.storage, name)
        conn = []
        for (k, v) in obj.conn.items():
            conn.append(k)

        if (len(conn) != 1):
            return

        if (obj.location[0] == conn[0]):
            return

        self.storage.move_chunk(name, [conn[0]]) 
